import { useCall } from '@/components';
import { forkHandler, uid } from '@/utils';
import React, { Children, cloneElement } from 'react';

const createUploader = (accept = '*', multiple = false) => {
  const input = document.createElement('input');
  const label = document.createElement('label');
  const id = uid().substr(2);
  label.for = id;
  input.id = id;
  input.type = 'file';
  input.accept = accept;
  input.multiple = multiple;
  input.style.display = 'none';
  label.style.position = 'absolute';
  label.style.zIndex = '-999';

  label.appendChild(input);
  document.body.appendChild(label);

  return new Promise((resolve, reject) => {
    let resolved = false;

    function onEnd() {
      resolved = true;
      input.removeEventListener('change', onChange);
      window.removeEventListener('focus', onFocus);
      input.parentNode?.removeChild(input);
      label.parentNode?.removeChild(label);
    }

    function onChange() {
      if (resolved) return;
      resolve(input.files);
      onEnd();
    }

    function onFocus() {
      setTimeout(() => {
        if (resolved) return;
        reject(new Error('user cancel'));
        onEnd();
      }, 1e3);
    }

    input.addEventListener('change', onChange);
    window.addEventListener('focus', onFocus);

    label.click();
  });
};

function ClickUpload({ accept = '*', multiple = false, onUpload, onCancel = console.error, children, ...props }) {
  Children.only(children);

  const onClick = useCall(
    forkHandler(
      children.props.onClick,
      () => {
        createUploader(accept, multiple).then((files) => {
          onUpload?.(files);
        }, onCancel);
      },
      true,
    ),
  );

  return cloneElement(children, { ...props, onClick });
}

ClickUpload.create = createUploader;

export default ClickUpload;
